package server.resources;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import json.JSONObjectWrapper;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;

import server.database.AbstractTable;
import server.database.DatabaseColumn;
import server.database.DatabaseService;
import server.database.query.IQueryResult;
import server.servlet.AbstractEntityServlet;
import utils.StringUtils;

import com.google.common.collect.Lists;

public class AreasServlet extends AbstractEntityServlet
{
	private static final long serialVersionUID = 9029098628136079645L;

	public static final String PATH = API + "/areas";

	public static final String AREA = "area";
	public static final String AREAS = "areas";

	public static final String AREA_CITIES = "area_cities";
	public static final String REMOVED_CITIES = "removed_cities";

	@Override
	protected String getEntityName()
	{
		return AREA;
	}

	@Override
	protected String getEntitiesName()
	{
		return AREAS;
	}

	@Override
	protected AreasTable getTable()
	{
		return (AreasTable) DatabaseService.getInstance().getTable(AreasTable.TABLE_NAME);
	}

	protected CitiesTable getCitiesTable()
	{
		return (CitiesTable) DatabaseService.getInstance().getTable(CitiesTable.TABLE_NAME);
	}

	@Override
	protected void doAddPost(JSONObjectWrapper request, JSONObject output) throws ServletException, IOException
	{
		JSONObjectWrapper area = request.getJsonValue(getEntityName());

		Map<DatabaseColumn, String> mpValues = parseEntityValues(area, getTable());
		IQueryResult result = getTable().insert(mpValues);

		int iAreaID = result.getAutoIncrementedValue();

		JSONArray cities = area.getJsonArray(AREA_CITIES);
		CitiesTable citiesTable = getCitiesTable();
		for (Object cityObject : cities)
		{
			JSONObjectWrapper city = new JSONObjectWrapper((JSONObject) cityObject);

			Map<DatabaseColumn, String> mpCityValues = parseEntityValues(city, citiesTable);
			mpCityValues.put(CitiesTable.AREA_ID, String.valueOf(iAreaID));

			citiesTable.insert(mpCityValues);
		}

		if (result.getResult() == IQueryResult.SUCESS)
		{
			output.put(RESULT, true);
		}
		else
		{
			// TODO - remove here all cities for this AREA_ID and remove AREA_ID
			// from table
			setFail(output, UNEXPECTED_ERROR, result.getError());
		}
	}

	@Override
	protected void doUpdatePostSpecific(JSONObjectWrapper request, Map<DatabaseColumn, String> mpValues)
	{
		JSONObjectWrapper area = request.getJsonValue(getEntityName());
		String sAreaID = area.getStringValue(getTable().ID.getName());

		JSONArray cities = area.getJsonArray(AREA_CITIES);
		CitiesTable citiesTable = getCitiesTable();
		for (Object cityObject : cities)
		{
			JSONObjectWrapper city = new JSONObjectWrapper((JSONObject) cityObject);
			String sCityID = city.getStringValue(getTable().ID.getName());
			Map<DatabaseColumn, String> mpCityValues = parseEntityValues(city, citiesTable);

			if (StringUtils.isEmpty_DB(sCityID))
			{
				mpCityValues.put(CitiesTable.AREA_ID, sAreaID);

				citiesTable.insert(mpCityValues);
			}
			else
			{
				citiesTable.update(sCityID, mpCityValues);
			}

		}

		JSONArray removedCities = area.getJsonArray(REMOVED_CITIES);
		for (Object cityObject : removedCities)
		{
			JSONObjectWrapper city = new JSONObjectWrapper((JSONObject) cityObject);

			String sCityId = city.getStringValue(getTable().ID.getName());
			citiesTable.deleteID(sCityId);
		}
	}

	@Override
	protected void doDeletePostSpecific(JSONObjectWrapper request)
	{
		String sAreaID = request.getStringValue(getTable().ID.getName());
		CitiesTable cities = getCitiesTable();
		cities.delete(Arrays.asList(CitiesTable.AREA_ID), Arrays.asList(sAreaID));
	}

	@Override
	protected final void doGetSpecific(HttpServletRequest request, HttpServletResponse response, JSONObject output) throws ServletException, IOException
	{
		IQueryResult queryResult = null;

		List<DatabaseColumn> lstFields = Lists.newArrayList();
		List<String> lstValues = Lists.newArrayList();

		String sID = request.getParameter(getTable().ID.getName());
		if (StringUtils.isEmpty_DB(sID))
		{
			setSpecificGetQuery(request, lstFields, lstValues);

			queryResult = getTable().getAllEntities(lstFields, lstValues, AbstractTable.AND);
			output.put(QUERY_RESULT, queryResult.getResult());
		}
		else
		{
			queryResult = querySpecificID(request, lstFields, lstValues);
			output.put(QUERY_RESULT, queryResult.getResult());
		}

		if (queryResult.getResult() == IQueryResult.SUCESS)
		{
			output.put(RESULT, true);

			JSONArray areas = new JSONArray();
			buildEntityValues(queryResult.getResultValues(), areas, getTable());
			CitiesTable citiesTable = getCitiesTable();

			for (Object areaObject : areas)
			{
				JSONObjectWrapper area = new JSONObjectWrapper((JSONObject) areaObject);

				IQueryResult citiesQuery = citiesTable.getAllEntities(Arrays.asList(citiesTable.AREA_ID), Arrays.asList(area.getStringValue(getTable().ID.getName())), getTable().AND);
				if (citiesQuery.getResult() == IQueryResult.SUCESS)
				{
					JSONArray cities = new JSONArray();
					buildEntityValues(citiesQuery.getResultValues(), cities, citiesTable);
					area.putValue(AREA_CITIES, cities);
				}

			}

			output.put(getEntitiesName(), areas);

		}
		else if (queryResult.getResult() != IQueryResult.NO_RESULTS)
		{
			setFail(output, UNEXPECTED_ERROR, UNEXPECTED_ERROR);
		}
	}

}
